import * as bfun from '../../core/fbyte.js';
/**
 * 专门用于编码 (用树结构编码)
 * 仅支持 uint8array key
 */
//根节点 是0层
//每往下 加1层
const BNode = {
	newCreate(父, 层, b, code) {
		let self = {
			pnd:父,
			pass: 0, //经过权重
			level: 层 || 0,
			child: new Map(), //子节点
			code, //id
			b	//key		
		};
		return self;
	},
	up(node, callback) {
		if (node) {
			callback(node)
			if (node.pnd) {
				BNode.up(node.pnd, callback);
			}
		}
	},

	down(node, callback) {
		if (node == null) return;
		let ta = this;
		//console.log(node)
		node.child.forEach(function(nd, b, map) {
			//vue 扩展对象的属性 extend 导致的问题
			if (nd == null) return;
			let flag = callback(node,nd, b);
			if (flag) return;
			ta.down(nd, callback);
		});
	},
	/**
	 * 插入固定长度的keys改变树的结构
	 * @param {Object} node  树根节点 node 是第0层
	 * @param {Object} bytes  插入不限定长度的字节
	 * @param {Object} level  表示节点在第几level  从第一层开始
	 */
	setn(node, bytes, level) {
		//为空跳过	
		if (bytes == null || bytes.length == 0) return;
		level = level || 1;
		if (level > bytes.length) return;
		let b0 = bytes[level - 1];
		let bk = bytes.subarray(0, level);
		//console.log(b0)
		//如果节点为空创建一个
		let nd = node.child.get(b0);
		if (nd == null) {
			nd = this.newCreate(node, level, b0, bk);
			node.child.set(b0, nd);
		}
		//创建子节点
		nd.pass++;
		//继续下钻
		if (bytes.length > level) {
			level++;
			this.setn(nd, bytes, level);
		}
	},
	/*
	插入不固定的长度
	如果树节点已经存在,挂在树节点下面,
	如果不存在,添加到父节点后面
	*/	
	putNofixed(node, bytes){
		let id=1;
		let ta = this;		
		function add(nd1, bs,level){
			if (bs == null || bs.length == 0) return;
			level=level||1;	
			let b0=bs[0];
			bs=bs.subarray(1);
			let nd2=nd1.child.get(b0);
			if (nd2==null)  {
				nd2 = ta.newCreate(nd1, level, b0, id++);
				nd1.child.set(b0, nd2);
				add(node, bs,0);			
			}else{
				nd2.pass++;
				add(nd2, bs,++level);
			}
		}
		add(node,bytes,0);	
	},
	//以下两个方法 适用于map场合
	/**
	 * 
	 * @param {Object} node 树根节点
	 * @param {Object} bytes  插入不限定长度的字节
	 * @param {Object} value  设置末尾节点附加值
	 */
	testput(node, bytes, value) {
		if (node == null || bytes == null || bytes.length == 0) return null;
		let b0 = bytes[0];
		let nd = node.child.get(b0);
		if (nd == null) {
			nd = BNode.newCreate(node)
			node.child.set(b0, nd);
		}
		if (bytes.length == 1) {
			nd.value = value;
		} else {
			this.put(nd, bytes.subarray(1));
		}
	},
	getValue(node, key) {
		if (node == null || key == null || key.length == 0) return null;
		let b0 = key[0];
		let nd = node.child.get(b0);
		if (nd == null) return null;
		if (key.length == 1) {
			return nd;
		} else {
			return this.getValue(nd, key.subarray(1));
		}
	},
	get(node,key){
		let ta = this;
		if (key==null||key.length==0) return node;			
		if (node&&node.child.size>0){
			let nd=node.child.get(key[0]);
			if (nd==null) return null;
			return ta.get(nd,key.subarray(1));	
		}
	},			
	view(node) {	
		this.down(node,function(pnd,nd, key) {
			if (nd)
			console.log(pnd&&pnd.b,'--', nd.b,nd.level,nd.code)
		});
	},
	//树的层必须大于1,否则直接输出树
	treeToList(root) {
		let dict = [];
		let ta = this;
		let 最大层 = 0;

		function add1(node) {
			let n = node.level;
			if (dict[n - 1] == null)
				dict[n - 1] = [];
			最大层 = Math.max(最大层, n);
			//元素,子节点个数
			dict[n - 1].push([node.b, node.child.size]);
		}
		ta.down(root, function(pnd,nd, k) {
			if (nd.level > 0) {
				add1(nd);
			}
		});

		function dict_ui8() {
			let n = 0;
			let arr =[最大层];
			for (let l = 最大层 - 1; l >= 0; l--) {
				//console.log(l, dict[l]);
				let ar = dict[l];
				let maxlen = ar.length;
				arr.push(bfun.intToByte4(maxlen));
				arr.push(ar.flat());
			}
			return arr.flat();
		}
		let uilist= new Uint8Array(dict_ui8());
		
		return uilist;
	},
	listToTree(uilist) {		
		let ta=this;
		function mount(narr1,narr2){		
			//把narr2 挂到 narr1下面			
			let j=0,k=0;		
			let nd;		
			while(0<narr2.length){		
				if (k==0&&j<narr1.length){								
					nd=narr1[j];
					k=nd.code;//子元素个数
					j++;
				}
				if (k>0){
					nd.child.set(narr2[0].b,narr2[0]);
					narr2.shift();
					k--;
				}
				
			}
			//console.log(narr1,narr2);
		}
		function step1(list,层,narr2){
			//console.log(list.length,list.toString(),narr2&&narr2.toString());
			let k=0;//list 数组的偏移量
			let len=bfun.byte4ToInt(list,k);
			let n=len*2;
			k+=4;
			let arr=list.subarray(k,k+n);
			k+=n;
		
			var narr1=[];
			for(let i=0;i<n;i+=2){
				let nd=ta.newCreate(null,层,arr[i],arr[i+1]);
				narr1.push(nd);				
			}
			if (narr1!=null&&narr1.length>0&&narr2!=null){
				mount(narr1,narr2);
			}
			list=list.subarray(k);
			if (list.length>0)
				return step1(list,层-1,narr1);	
			else
				return narr1;
		}
		//console.log(uilist)
		let maxlevel=uilist[0];
		let root=ta.newCreate();
		let arr0=step1(uilist.subarray(1),maxlevel);
	
		for(let i=0;i<arr0.length;i++){
			root.child.set(arr0[i].b,arr0[i]);
		}
		return root;
	}
};


export default BNode;
